#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
@desc: .

@Project: kuberCloud 
@File: api.py
@Author: admin
@Date: 2023/8/23 14:06 
"""
import base64
import json
import time
from hashlib import sha1

import requests

from kuberCloudTest.common.kuberlogs.log import kuberCloudLog
from kuberCloudTest.common.utils import _getUrl
from kuberCloudTest.config import GlobalVars
from kuberCloudTest.exception import KuberCloudException


class KuberCloudHttpRequest:
    _AUTH_TOKEN = 'X-AUTH-TOKEN'

    _GET = 'GET'
    _POST = 'POST'
    _UPDATE = 'UPDATE'
    _DELETE = 'DELETE'

    def __init__(self, accessToken):
        self._accessToken = accessToken

        if not self._accessToken:
            raise KuberCloudException('params error', 'accessToken is none')

        self._check()

        self._accessKeySecret = GlobalVars.ACCESS_KEY_SECRET
        self._host = GlobalVars.HOST
        self._port = GlobalVars.PORT

    @staticmethod
    def _check():
        if not GlobalVars.HOST or not GlobalVars.PORT:
            raise KuberCloudException('params error', 'host or port is none')
        if not GlobalVars.ACCESS_KEYID or not GlobalVars.ACCESS_KEY_SECRET:
            raise KuberCloudException('params error', 'accessKeySecret or accessKeySecret is none')

    def _getAuthorization(self, method, uri):
        if not uri:
            raise KuberCloudException('params error', 'uri is none')
        access = self._accessKeySecret + method + uri
        Signature = base64.b64encode(sha1(access.encode('utf-8')).digest()).decode('utf-8')
        authorization = self._accessToken + ":" + Signature
        if not authorization:
            raise KuberCloudException('params error', 'failed to verify access-token')
        return authorization

    def _getHeaders(self, authorization, **kwargs):
        headers = {self._AUTH_TOKEN: authorization}
        if 'contentType' in kwargs.keys():
            headers['content-type'] = kwargs['contentType']
        return headers

    def get(self, uri, params=None):
        try:
            params = params if params else {}
            headers = self._getHeaders(self._getAuthorization(self._GET, uri))
            url = _getUrl(self._host, self._port, uri)
            response = requests.get(url, params=params, headers=headers)
            return self._parseSyncResponse(response)
        except KuberCloudException as kuberCloudException:
            kuberCloudLog.error('internal error: execute get request failed: {}'.format(kuberCloudException.message))
            raise KuberCloudException(kuberCloudException.reason, kuberCloudException.message)
        except Exception as exception:
            kuberCloudLog.error('internal error: execute get request failed: {}'.format(exception.args[0]))
            raise KuberCloudException('internal error', exception.args[0])

    def post(self, uri, params=None, data=None):
        try:
            is_async = False
            if params is None:
                params = {}
            else:
                if 'logAction' in params.keys():
                    is_async = params['logAction']['async']
            if data is None:
                data = {}
            else:
                if 'logAction' in data.keys():
                    is_async = data['logAction']['async']
                data = json.dumps(data)
            headers = (
                self._getHeaders(self._getAuthorization(self._POST, uri), contentType='application/json;charset=UTF-8'))
            url = _getUrl(self._host, self._port, uri)
            response = requests.post(url, data=data, params=params, headers=headers)
            if not is_async:
                # 同步任务直接返回响应
                return self._parseSyncResponse(response)
            return self._parseAsyncResponse2(response)
        except KuberCloudException as kuberCloudException:
            kuberCloudLog.error('internal error: execute post request failed: {}'.format(kuberCloudException.message))
            raise KuberCloudException(kuberCloudException.reason, kuberCloudException.message)
        except Exception as exception:
            kuberCloudLog.error('internal error: execute post request failed: {}'.format(exception.args[0]))
            raise KuberCloudException('internal error', exception.args[0])

    @staticmethod
    def _parseResponse(response):
        """response
        parse response
        :param response: http request response
        :return:
        """
        status_code = response.status_code
        if status_code != 200:
            raise KuberCloudException('internal error', 'internal error')
        content = json.loads(response.content.decode())
        code = content['code']
        if code != 1:
            raise KuberCloudException('internal error', content['msg'])
        return content

    @staticmethod
    def _getAsyncTaskFromResponseReaders(response):
        """
        analysis response headers
        :param response: http request response
        :return:
        """
        headers = response.headers
        header_store = headers._store
        asyncTask = header_store.get('x-task-uuid', None)
        asyncTaskPoll = header_store.get('x-task-poll-url', None)
        asyncTaskId = None
        asyncTaskPollUri = None
        if asyncTask:
            asyncTaskId = asyncTask[1]
        if asyncTaskPoll:
            asyncTaskPollUri = asyncTaskPoll[1]
        if not asyncTaskId and not asyncTaskPollUri:
            raise KuberCloudException('async task error', 'get async task error')
        return asyncTaskId, asyncTaskPollUri

    def _parseSyncResponse(self, response):
        """
        parse sync response
        :param response: http request response
        :return:
        """
        return self._parseResponse(response)

    def _parseAsyncResponse(self, response):
        """
        parse async response
        :param response: http request response
        :return:
        """
        self._parseResponse(response)
        # check async task
        asyncTaskId, asyncTaskPollUri = self._getAsyncTaskFromResponseReaders(response)
        asyncTaskPollUrl = _getUrl(self._host, self._port, asyncTaskPollUri)
        if not asyncTaskPollUrl:
            raise KuberCloudException('async task error', 'get async task url error')
        asyncTaskId, asyncTaskPollUri = self._getAsyncTaskFromResponseReaders(response)
        time.sleep(3)
        while True:
            asyncTaskResponse = \
                requests.get(asyncTaskPollUrl,
                             headers=self._getHeaders(self._getAuthorization(self._GET, asyncTaskPollUri)))
            if asyncTaskResponse.status_code != 200:
                raise KuberCloudException('internal error', 'internal error')
            asyncTaskContent = json.loads(asyncTaskResponse.content.decode())
            code = asyncTaskContent['code']
            if code != 1:
                raise KuberCloudException('analysis async task error', asyncTaskContent['returnResult'])
            asyncTaskResult = asyncTaskContent['actionResult']
            if asyncTaskResult == 1:
                return asyncTaskContent
            elif asyncTaskResult == 2:
                continue
            elif asyncTaskResult == 0 or asyncTaskResult == -1:
                # return asyncTaskContent
                raise KuberCloudException('execute async task error', asyncTaskContent['returnResult'])
            else:
                # return asyncTaskContent
                raise KuberCloudException('execute async task timeout', asyncTaskContent['returnResult'])

    def _parseAsyncResponse2(self, response):
        """
        parse async response
        :param response: http request response
        :return:
        """
        content = self._parseResponse(response)
        asyncTaskId, asyncTaskPollUri = self._getAsyncTaskFromResponseReaders(response)

        content['x-task-uuid'] = asyncTaskId
        content['x-task-poll-url'] = asyncTaskPollUri
        return content
